package com.swsc.solarverse.service.schedule;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.swsc.solarverse.common.config.ResParams;
import com.swsc.solarverse.common.enums.FaultCategoryEnum;
import com.swsc.solarverse.common.util.CodeUtils;
import com.swsc.solarverse.common.util.DefectHelper;
import com.swsc.solarverse.common.util.LocalDateTimeUtils;
import com.swsc.solarverse.common.util.SnowflakeSquence;
import com.swsc.solarverse.dao.entity.DefectDO;
import com.swsc.solarverse.dao.entity.DefectDefinitionDO;
import com.swsc.solarverse.dao.entity.StationModuleDO;
import com.swsc.solarverse.dao.entity.analysis.StringEfficiencyRecordDO;
import com.swsc.solarverse.dao.entity.forward.ForwardStringLeDiagnoseRecordDO;
import com.swsc.solarverse.model.CorporationQueryBO;
import com.swsc.solarverse.model.CorporationStationBO;
import com.swsc.solarverse.service.IDefectDefinitionService;
import com.swsc.solarverse.service.IDefectService;
import com.swsc.solarverse.service.IStationModuleService;
import com.swsc.solarverse.service.analysis.IStringEfficiencyRecordService;
import com.swsc.solarverse.service.forward.IForwardStringLeDiagnoseRecordService;
import com.swsc.solarverse.service.sys.ICorporationStationService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Author Administrator
 * @Date 2025/7/22 17:07
 * @Version 1.0
 * @Description
 */
@lombok.extern.slf4j.Slf4j
@org.springframework.stereotype.Service
public class StringLeDiagnoseScheduleTaskService {
    private final ICorporationStationService corporationStationService;
    private final IStationModuleService stationModuleService;
    private final IDefectDefinitionService defectDefinitionService;
    private final IStringEfficiencyRecordService stringEfficiencyRecordService;
    private final IForwardStringLeDiagnoseRecordService forwardStringLeDiagnoseRecordService;
    private final IDefectService defectService;


    public StringLeDiagnoseScheduleTaskService(ICorporationStationService corporationStationService,
                                               IStationModuleService stationModuleService,
                                               IDefectDefinitionService defectDefinitionService,
                                               IStringEfficiencyRecordService stringEfficiencyRecordService,
                                               IForwardStringLeDiagnoseRecordService forwardStringLeDiagnoseRecordService,
                                               IDefectService defectService) {
        this.corporationStationService = corporationStationService;
        this.stationModuleService = stationModuleService;
        this.defectDefinitionService = defectDefinitionService;
        this.stringEfficiencyRecordService = stringEfficiencyRecordService;
        this.forwardStringLeDiagnoseRecordService = forwardStringLeDiagnoseRecordService;
        this.defectService = defectService;
    }

    public List<CorporationStationBO> listCorporationStations() {
        return corporationStationService.listCorporationStations(new CorporationQueryBO());
    }

    @Transactional(rollbackFor = Exception.class)
    public void diagnose(CorporationStationBO stationBo, LocalDateTime dataTime, LocalDateTime now) {
        if (null != stationBo && null != dataTime) {
            List<ForwardStringLeDiagnoseRecordDO> diagnoseRecordDos = forwardStringLeDiagnoseRecordService.list(Wrappers.lambdaQuery(ForwardStringLeDiagnoseRecordDO.class)
                    .eq(ForwardStringLeDiagnoseRecordDO::getTenantNo, stationBo.getTenantNo())
                    .eq(ForwardStringLeDiagnoseRecordDO::getOrganNo, stationBo.getOrganNo())
                    .eq(ForwardStringLeDiagnoseRecordDO::getDiagnoseTime, dataTime)
                    // 电流或电压比例大于阈值
                    .and(wr ->
                            wr.gt(ForwardStringLeDiagnoseRecordDO::getLowU, ResParams.analysisStrLeDiagnoseLowUThreshold)
                                    .or()
                                    .gt(ForwardStringLeDiagnoseRecordDO::getLowI, ResParams.analysisStrLeDiagnoseLowIThreshold))
            );
            if (CollectionUtils.isNotEmpty(diagnoseRecordDos)) {
                Map<String, DefectDefinitionDO> defectDefinitionDoMap = defectDefinitionService.getDefectDefinitionMap(FaultCategoryEnum.LE.getCode());
                List<StationModuleDO> stationModuleDos = stationModuleService.listStationModules(stationBo.getTenantNo(), stationBo.getOrganNo());
                Float moduleAvgPower = 0F;
                if (CollectionUtils.isNotEmpty(stationModuleDos)) {
                    Float totalModulePower = 0F;
                    Integer totalModuleNum = 0;
                    for (StationModuleDO stationModuleDo : stationModuleDos) {
                        if (null != stationModuleDo.getNum() && null != stationModuleDo.getPower()) {
                            totalModuleNum += stationModuleDo.getNum();
                            totalModulePower += stationModuleDo.getPower() * stationModuleDo.getNum();
                        }
                    }
                    if (totalModuleNum == 0) {
                        totalModuleNum = stationBo.getModelNum();
                    }
                    moduleAvgPower = totalModulePower / totalModuleNum;
                }
                if (moduleAvgPower < 100) {
                    moduleAvgPower = 400F;
                }
                // 平均每块组件年损耗kWh
                Float moduleAvgLoss = moduleAvgPower / 1000 * (null == stationBo.getAnnualUseHour() ? 1600F : stationBo.getAnnualUseHour());
                List<DefectDO> defectDos = new ArrayList<>(diagnoseRecordDos.size());
                String taskNo = CodeUtils.generateTaskNo(stationBo.getOrganNo(), dataTime, 1);
                String taskSubNo = taskNo + "01";
                SnowflakeSquence squence = new SnowflakeSquence();
                for (ForwardStringLeDiagnoseRecordDO diagnoseRecordDo : diagnoseRecordDos) {
                    DefectDO defectDo = new DefectDO();
                    defectDo.setCreateTime(now);
                    defectDo.setTenantNo(stationBo.getTenantNo());
                    defectDo.setOrganNo(stationBo.getOrganNo());
                    defectDo.setOrganName(stationBo.getOrganName());
                    defectDo.setDeviceCode(diagnoseRecordDo.getDeviceCode());
                    defectDo.setDeviceName(diagnoseRecordDo.getDeviceCode());
                    String faultReason = DefectHelper.parseLeFault(diagnoseRecordDo.getLowI(), diagnoseRecordDo.getLowU(),
                            ResParams.analysisStrLeDiagnoseLowIThreshold, ResParams.analysisStrLeDiagnoseLowUThreshold);

                    defectDo.setLossU(null != diagnoseRecordDo.getLossU() ? diagnoseRecordDo.getLossU().floatValue() : 0F);
                    defectDo.setLossI(null != diagnoseRecordDo.getLossI() ? diagnoseRecordDo.getLossI().floatValue() : 0F);
                    defectDo.setLossP(null != diagnoseRecordDo.getLossP() ? diagnoseRecordDo.getLossP().floatValue() : 0F);
                    defectDo.setStringIndex(diagnoseRecordDo.getDeviceId().byteValue());
                    defectDo.setFaultReason(faultReason);
                    defectDo.setTaskNo(taskNo);
                    defectDo.setTaskSubNo(taskSubNo);
                    defectDo.setBatchNo(taskSubNo);
                    defectDo.setFaultCategory(FaultCategoryEnum.LE.getCode());
                    defectDo.setPatrolTime(dataTime);
                    defectDo.setPatrolActualTime(dataTime);
                    if (StringUtils.isNotBlank(faultReason)) {
                        defectDo.setFaultName(faultReason);
                    } else {
                        defectDo.setFaultName("组串低效");
                    }
                    // 无经纬度
                    // processLngLat(defectDo, deviceVectorMap);
//                    if (null != deviceVectorMap && deviceVectorMap.size() > 0) {
//                        if (null == defectDo.getLatitude() || null == defectDo.getLongitude()) {
//                            // 如果获取不到经纬度, 则不上传
//                            continue;
//                        }
//                    }
//

                    DefectDefinitionDO defectDefinitionDo = defectDefinitionDoMap.get(FaultCategoryEnum.LE.getCode() + "-" + defectDo.getFaultName());
                    if (null != defectDefinitionDo) {
                        defectDo.setFaultLevel(defectDefinitionDo.getDefectLevel().toString());
                        if (StringUtils.isBlank(defectDo.getFaultReason())) {
                            defectDo.setFaultReason(defectDefinitionDo.getDefectReason());
                        }


                    }
                    defectDo.setDefectNo(squence.nextId());
                    defectDos.add(defectDo);
                }
                if (CollectionUtils.isNotEmpty(defectDos)) {
                    log.info("组串低效诊断: 获取电量损失 {}", defectDos.size());
                    processLossE(stationBo, defectDos, dataTime);
                    defectService.remove(Wrappers.lambdaQuery(DefectDO.class)
                            .eq(DefectDO::getTenantNo, stationBo.getTenantNo())
                            .eq(DefectDO::getOrganNo, stationBo.getOrganNo())
                            .eq(DefectDO::getTaskNo, taskNo)
                            .eq(DefectDO::getTaskSubNo, taskSubNo)
                            .eq(DefectDO::getBatchNo, taskSubNo)
                    );
                    log.info("组串低效诊断: 保存结果 {}", defectDos.size());
                    defectService.saveBatch(defectDos);
                }
            }
        }
    }

    private void processLossE(CorporationStationBO stationBo, List<DefectDO> defectDos, LocalDateTime dataTime) {
        if (null != stationBo && null != dataTime && CollectionUtils.isNotEmpty(defectDos)) {
            List<StringEfficiencyRecordDO> efficiencyRecordDos = stringEfficiencyRecordService.list(Wrappers.lambdaQuery(StringEfficiencyRecordDO.class)
                    .eq(StringEfficiencyRecordDO::getTenantNo, stationBo.getTenantNo())
                    .eq(StringEfficiencyRecordDO::getOrganNo, stationBo.getOrganNo())
                    .eq(StringEfficiencyRecordDO::getDataTime, LocalDateTimeUtils.getDayStart(dataTime)));
            if (CollectionUtils.isNotEmpty(efficiencyRecordDos)) {
                for (DefectDO defectDo : defectDos) {
                    StringEfficiencyRecordDO efficiencyRecordDo = efficiencyRecordDos.stream().filter(erd -> Objects.equals(defectDo.getDeviceName(), erd.getDeviceCode())).findFirst().orElse(null);
                    if (null == efficiencyRecordDo && null != defectDo.getStringIndex()) {
                        String deviceCode = CodeUtils.getCode(defectDo.getDeviceCode(), defectDo.getStringIndex());
                        efficiencyRecordDo = efficiencyRecordDos.stream().filter(erd -> Objects.equals(deviceCode, erd.getDeviceCode())).findFirst().orElse(null);
                    }
                    if (null != efficiencyRecordDo && null != efficiencyRecordDo.getLossE()) {
                        defectDo.setLossE(efficiencyRecordDo.getLossE().floatValue());
                    }
                }
            }
        }
    }
}
